﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Ionic.Zip;
using System.IO;
using Admin.Models;
using System.Text;
using HtmlAgilityPack;

namespace Admin.Controllers
{
    public class HomeController : Controller
    {
        private const string SolutionTempLocation = @"C:\Lab\dynamic-mvc\Asp.net MVC MVC 4 Integration\Admin\Content\temp\";
        private const string PluginTemplateLocation = @"C:\Lab\dynamic-mvc\Asp.net MVC MVC 4 Integration\Admin\Content\PluginTemplate\";
        private const string ActionMethodFormat = @"public ActionResult {0}(Dictionary<BusinessLayer.Enums.DataBagKey, IMultipleResults> data = null) 
                                                    {{
                                                        return View();
                                                    }}
                                                    ";

        public ActionResult Index()
        {
            var viewModel = new ViewModel();
            string zip = @"C:\template\ecomm.zip";
            string root = "";
            ExtractMockups(zip, out root);
            List<FileInfo> FileCollection = new List<FileInfo>();
            FileCollection = TraverseTree(root);
            viewModel.FileCollection = FileCollection;
            return View(viewModel);
        }

        public ActionResult ProcessPages()
        {
            var pageList = Request.Cookies["ProcessPages"];
            List<string> pages = new List<string>();
            if (pageList != null)
                pages = HttpUtility.UrlDecode(pageList.Value).Split(',').ToList<string>();
            GeneratePlugins(pages);

            return View();
        }

        private void GeneratePlugins(List<string> pages)
        {

            foreach (var item in pages)
            {
                HtmlDocument htmlDocument = new HtmlDocument();
                htmlDocument.Load(item);
                foreach (HtmlNode componentNode in htmlDocument.DocumentNode.SelectNodes("//div[@data-type='component']"))
                {
                    string pluginName = componentNode.Attributes["data-name"].Value;
                    DirectoryCopy(PluginTemplateLocation, string.Concat(SolutionTempLocation, pluginName), true);
                    DirectoryRename(pluginName);
                    FileRename(pluginName);
                    var modesCSV = componentNode.Attributes.Where(p => p.Name.Contains("data-mode")).Select(q => q.Value).FirstOrDefault();
                    SetControllerActions(pluginName, modesCSV);
                }
            }
        }

        private void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
        {
            DirectoryInfo dir = new DirectoryInfo(sourceDirName);
            DirectoryInfo[] dirs = dir.GetDirectories();

            // If the source directory does not exist, throw an exception.
            if (!dir.Exists)
            {
                throw new DirectoryNotFoundException(
                    "Source directory does not exist or could not be found: "
                    + sourceDirName);
            }

            // If the destination directory does not exist, create it.
            if (!Directory.Exists(destDirName))
            {
                Directory.CreateDirectory(destDirName);
            }


            // Get the file contents of the directory to copy.
            FileInfo[] files = dir.GetFiles();

            foreach (FileInfo file in files)
            {
                // Create the path to the new copy of the file.
                string temppath = Path.Combine(destDirName, file.Name);

                // Copy the file.
                file.CopyTo(temppath, false);
            }

            // If copySubDirs is true, copy the subdirectories.
            if (copySubDirs)
            {
                foreach (DirectoryInfo subdir in dirs)
                {
                    // Create the subdirectory.
                    string temppath = Path.Combine(destDirName, subdir.Name);

                    // Copy the subdirectories.
                    DirectoryCopy(subdir.FullName, temppath, copySubDirs);
                }
            }
        }

        //rename directory name with token
        private void DirectoryRename(string plugin)
        {
            IEnumerable<string> list = Directory.GetDirectories(string.Concat(SolutionTempLocation, plugin), "$plugin$", SearchOption.AllDirectories);
            foreach (var item in list)
            {
                DirectoryInfo dir = new DirectoryInfo(item);
                dir.MoveTo(item.Replace("$plugin$", plugin));
            }
        }

        //rename files and replace tokens inside filess
        private void FileRename(string plugin)
        {
            string[] filePaths = Directory.GetFiles(string.Concat(SolutionTempLocation, plugin), "*.*", SearchOption.AllDirectories);
            string currentFile = string.Empty;

            //replace token in files
            foreach (string file in filePaths)
            {
                currentFile = System.IO.File.ReadAllText(file);
                if (currentFile.Contains("$plugin$"))
                {
                    currentFile = currentFile.Replace("$plugin$", plugin);
                    using (StreamWriter streamWriter = new StreamWriter(file))
                    {
                        streamWriter.Write(currentFile);
                    }
                }
            }
            foreach (string file in filePaths)
            {
                string currentFileName = Path.GetFullPath(file);
                currentFileName = currentFileName.Replace("$plugin$", plugin);
                System.IO.File.Move(file, currentFileName);
            }
        }

        private void SetControllerActions(string plugin, string modesCSV)
        {
            IEnumerable<string> list = Directory.GetFiles(string.Concat(SolutionTempLocation, plugin), string.Concat("*.cs"), SearchOption.AllDirectories);
            string currentFile = string.Empty;

            //replace token in files
            foreach (string file in list)
            {
                currentFile = System.IO.File.ReadAllText(file);
                if (currentFile.Contains("$modes$"))
                {
                    StringBuilder sb = new StringBuilder();
                    var modes = modesCSV.Split(',');
                    foreach (var mode in modes)
                    {
                        sb.Append(string.Format(ActionMethodFormat, modes));
                    }
                    currentFile = currentFile.Replace("$modes$", sb.ToString());

                    using (StreamWriter streamWriter = new StreamWriter(file))
                    {
                        streamWriter.Write(currentFile);
                    }
                }
            }

        }

        private void ExtractMockups(string template, out string extracPath)
        {
            string unpackDirectory = @"C:\template\temp";
            using (ZipFile zip1 = ZipFile.Read(template))
            {
                // here, we extract every entry, but we could extract conditionally
                // based on entry name, size, date, checkbox status, etc.  
                foreach (ZipEntry e in zip1)
                {
                    e.Extract(unpackDirectory, ExtractExistingFileAction.OverwriteSilently);
                }
                extracPath = Path.Combine(Path.GetDirectoryName(template), "temp", Path.GetFileNameWithoutExtension(template));
            }
        }

        //http://msdn.microsoft.com/en-us/library/bb513869.aspx
        private List<FileInfo> TraverseTree(string root, bool Parse = false)
        {
            Stack<string> dirs = new Stack<string>(20);
            List<FileInfo> FileCollection = new List<FileInfo>();
            if (!System.IO.Directory.Exists(root))
            {
                throw new ArgumentException();
            }
            dirs.Push(root);
            while (dirs.Count > 0)
            {
                string currentDir = dirs.Pop();
                string[] subDirs;
                try
                {
                    subDirs = System.IO.Directory.GetDirectories(currentDir);
                }
                catch (UnauthorizedAccessException e)
                {
                    //Console.WriteLine(e.Message);
                    continue;
                }
                catch (System.IO.DirectoryNotFoundException e)
                {
                    //Console.WriteLine(e.Message);
                    continue;
                }

                string[] files = null;
                try
                {
                    files = System.IO.Directory.GetFiles(currentDir);
                }

                catch (UnauthorizedAccessException e)
                {

                    // Console.WriteLine(e.Message);
                    continue;
                }

                catch (System.IO.DirectoryNotFoundException e)
                {
                    //Console.WriteLine(e.Message);
                    continue;
                }
                foreach (string file in files)
                {
                    try
                    {
                        // Perform whatever action is required in your scenario.
                        System.IO.FileInfo fi = new System.IO.FileInfo(file);
                        if (fi.Extension == ".html")
                            FileCollection.Add(fi);
                    }
                    catch (System.IO.FileNotFoundException e)
                    {
                        // If file was deleted by a separate application 
                        //  or thread since the call to TraverseTree() 
                        // then just continue.
                        // Console.WriteLine(e.Message);
                        continue;
                    }
                }
                foreach (string str in subDirs)
                    dirs.Push(str);
            }

            return FileCollection;
        }
    }
}
